﻿using AJWPFAdmin.Core.Components.Views;
using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.GlobalEvents;
using AJWPFAdmin.Core.HardwareSDKS.Models;
using AJWPFAdmin.Core.Models;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Mvvm;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Modules.Main.Views;
using AJWPFAdmin.Services;
using AJWPFAdmin.Services.AppointAPI;
using AJWPFAdmin.Services.EF;
using DnsClient.Protocol;
using Masuit.Tools.Models;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Threading;
using static AJWPFAdmin.Modules.Main.ViewModels.DeviceScreenViewModel;

namespace AJWPFAdmin.Modules.Main.ViewModels
{
    public class ShippingRecordScrollViewerViewModel : ViewModelBase
    {
        private UserControl _userControl;

        private bool _loading = true;
        public bool Loading
        {
            get { return _loading; }
            set { SetProperty(ref _loading, value); }
        }

        private Visibility _emptyInfoVisibility;
        public Visibility EmptyInfoVisibility
        {
            get { return _emptyInfoVisibility; }
            set { SetProperty(ref _emptyInfoVisibility, value); }
        }

        private string _search;
        public string Search
        {
            get { return _search; }
            set
            {
                if (SetProperty(ref _search, value))
                {
                    _debounce.Trigger();
                }
            }
        }

        private ObservableCollection<ShippingRecordBindableWrapper> _records;
        public ObservableCollection<ShippingRecordBindableWrapper> Records
        {
            get { return _records; }
            set { SetProperty(ref _records, value); }
        }

        private long?[] _watchhouseIds;

        private IDialogService _dialogSvc;
        private IEventAggregator _eventAggregator;
        private Debounce _debounce;
        private AJConfigService _cfgSvc;
        private AppointAPISvc _appointSvc;

        public ShippingRecordScrollViewerViewModel(
            IDialogService dialogSvc,
            AJConfigService cfgSvc,
            AppointAPISvc appointSvc,
        IEventAggregator eventAggregator)
        {
            _watchhouseIds = new long?[0];
            _cfgSvc = cfgSvc;
            _appointSvc = appointSvc;
            EmptyInfoVisibility = Visibility.Visible;
            Records = new ObservableCollection<ShippingRecordBindableWrapper>();
            _dialogSvc = dialogSvc;
            _eventAggregator = eventAggregator;
            _eventAggregator.GetEvent<CarIdentificationPanelViewModel.CarIdentificationPassedEvent>()
                .Subscribe((newRecord) =>
                {
                    //Records.Insert(0, new ShippingRecordBindableWrapper(newRecord, _cfgSvc, _appointSvc));
                    _debounce.Trigger();
                });

            _eventAggregator.GetEvent<DeviceSetupProgressEvent>().Subscribe((progress) =>
            {
                if (progress.Loading || (progress.Devices?.Count).GetValueOrDefault() == 0)
                {
                    Loading = false;
                    return;
                }
                _watchhouseIds = progress.Devices.Select(p => new long?(p.WatchhouseId)).Distinct().ToArray();
                _debounce.Trigger();
            });

            _debounce = new Debounce(GetListFun, 1000);

        }

        private void GetListFun(params object[] args)
        {
            _userControl.Dispatcher.Invoke(async () =>
            {
                if (Records.Any(p => p.Uploading))
                {
                    MessageBox.Show("有正在上传的数据,请稍后操作", "提示", MessageBoxButton.OK);
                    return;
                }
                Records.Clear();
                await GetListAsync();
            });
        }

        private DelegateCommand<ShippingRecordBindableWrapper> _openDetailDialogCmd;
        public DelegateCommand<ShippingRecordBindableWrapper> OpenDetailDialogCmd =>
            _openDetailDialogCmd ?? (_openDetailDialogCmd = new DelegateCommand<ShippingRecordBindableWrapper>(ExecuteOpenDetailDialogCmd));

        void ExecuteOpenDetailDialogCmd(ShippingRecordBindableWrapper parameter)
        {
            if (parameter.Uploading)
            {
                MessageBox.Show("正在上传数据,请稍后操作", "提示", MessageBoxButton.OK);
                return;
            }
            var @params = new DialogParameters
            {
                { "data", parameter.Record }
            };
            _dialogSvc.ShowDialog(nameof(ShippingRecordDetial), @params, r =>
            {
                //if (r.Result == ButtonResult.OK)
                //{
                //    ExecuteSearchCmd(true);
                //}
            });
        }

        private DelegateCommand<UserControl> _controlLoadedCmd;
        public DelegateCommand<UserControl> ControlLoadedCmd =>
            _controlLoadedCmd ?? (_controlLoadedCmd = new DelegateCommand<UserControl>(ExecuteControlLoadedCmd));

        void ExecuteControlLoadedCmd(UserControl ctrl)
        {
            _userControl = ctrl;
        }

        private async Task GetListAsync()
        {
            Loading = true;

            using var db = DbService.GetDbContext(_cfgSvc);
            var records = await db.ShippingRecords.LikeOrLike(Search, p => p.CarNo)
                .Where(p => _watchhouseIds.Contains(p.WatchhouseId)
                            || _watchhouseIds.Contains(p.OutWatchhouseId))
                .OrderByDescending(p => p.Id).ToPagedListAsync(1, 50);

            EmptyInfoVisibility = records.Data.Count > 0 ? Visibility.Collapsed : Visibility.Visible;

            var orderList = records.Data.Select(p => new ShippingRecordBindableWrapper(p, _cfgSvc, _appointSvc))
                .OrderByDescending(p => p.Record.Id).ToList();

            Records.AddRange(orderList);

            Loading = false;
        }

    }

    public class ShippingRecordBindableWrapper : BindableBase
    {
        private bool _uploading;
        public bool Uploading
        {
            get => _uploading;
            set => SetProperty(ref _uploading, value);
        }

        private string _message;
        public string Message
        {
            get => _message;
            set => SetProperty(ref _message, value);
        }

        private ShippingRecord _record;
        public ShippingRecord Record
        {
            get => _record;
            set => SetProperty(ref _record, value);
        }

        private Random _random;
        private AJConfigService _cfgSvc;
        private AppointAPISvc _appointSvc;

        public ShippingRecordBindableWrapper(ShippingRecord record, AJConfigService cfgSvc, AppointAPISvc appointSvc)
        {
            _cfgSvc = cfgSvc;
            _appointSvc = appointSvc;

            //var typeId = (long)CarTypeEnum.免检车;
            // 注释掉, 上传还是放到了车牌识别面板
            //Uploading = record.TypeId != typeId && !record.Synchronized;
            //Message = record.TypeId != typeId
            //        ? (!record.Synchronized ? "上传中..." : "上传成功")
            //        : string.Empty;
            Uploading = false;
            Message = string.Empty;
            Record = record;
            _random = new Random(Guid.NewGuid().GetHashCode());

            if (Uploading)
            {
                var worker = new BackgroundWorker();

                worker.DoWork += (_, e) =>
                {
                    var rad = _random.Next(1000, 5000);
                    Thread.Sleep(rad);

                    e.Result = Upload(e.Argument as ShippingRecordBindableWrapper);
                };
                worker.RunWorkerCompleted += (_, e) =>
                {
                    Uploading = false;

                    if (e.Error != null)
                    {
                        Message = "上传失败";
                        Record.SyncResult = e.Error.Message;
                        return;
                    }

                    var uploadRet = e.Result as ProcessResult;

                    Message = uploadRet.Success ? "上传成功" : "上传失败";
                    Record.SyncResult = uploadRet.Success ? string.Empty : uploadRet.Message;
                };
                worker.RunWorkerAsync(this);
            }
        }

        private ProcessResult Upload(ShippingRecordBindableWrapper wrapper)
        {
            var carNo = wrapper.Record.CarNo;

            var id = wrapper.Record.Id;

            var result = new ProcessResult();

            using var db = DbService.GetDbContext(_cfgSvc);

            var dbRecord = db.ShippingRecords.FirstOrDefault(p => p.Id == id);

            var carSynchronized = db.Cars.Any(p => p.CarNo == carNo && p.Synchronized);
            //todo-xq
            //if(string.IsNullOrWhiteSpace(dbRecord.InGoodsName)|| dbRecord.InGoodsName=="空车")
            //{
            //    dbRecord.InGoodsName= db.Cars.
            //}

            // 并且车辆的基础台账信息也同步成功
            if (carSynchronized)
            {
                var resultTask = Task.Run(async () =>
                {
                    return await _appointSvc.API.UploadShippingRecordAsync(new ShippingRecordParams
                    {
                        Record = dbRecord,
                        Operation = DataOperationType.新增
                    });
                });

                resultTask.Wait();

                result = resultTask.Result;

                if (!result.Success)
                {
                    if (!result.Message.Contains("不能编辑"))
                    {
                        dbRecord.SyncResult = $"错误信息:{result.Message}";
                    }
                }
                else
                {
                    dbRecord.SyncResult = string.Empty;
                }
                if (_appointSvc.API.KeyDescription == "青岛" || _appointSvc.API.KeyDescription == "赣州" || _appointSvc.API.KeyDescription == "成都")
                {
                    dbRecord.Synchronized = true;
                }
                else
                {
                    // 从返回结果读取过车记录和物资的上传次数重新更新
                    var retCopy = result.Attach as UploadShippingRecordResponse;
                    retCopy ??= new UploadShippingRecordResponse();
                    //必须重新查出来保存, 否则报并发错误

                    dbRecord.Synchronized = retCopy.RecordNum > 0 || retCopy.GoodsNum > 0;
                    dbRecord.RecordNum += retCopy.RecordNum;
                    dbRecord.GoodsNum += retCopy.GoodsNum;
                }

            }
            else
            {
                dbRecord.SyncResult = "车辆台账信息未同步,请先同步车辆信息";
                result.SetError(dbRecord.SyncResult);
            }
            dbRecord.UpdateDate = DateTime.Now;
            db.Entry(dbRecord).State = EntityState.Modified;
            db.SaveChanges();

            return result;
        }
    }

    public class RecordEmissionStandardFilterConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is ShippingRecord rcd)
            {
                return rcd.TypeId == (long)CarTypeEnum.临时车
                    ? rcd.TypeName : rcd.EmissionStandard.ToString();
            }
            return "--";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
    public class RecordPassagewayWithDirectionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is ShippingRecord rcd)
            {
                return rcd.Direction == PassagewayDirection.进 ? rcd.PassagewayName : rcd.OutPassagewayName;
            }
            return string.Empty;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
}
